﻿//===============================================================================
// Magic OQL
//===============================================================================
// Copyright ?Magic Thought Corporation. All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// Richie (http://www.cnblogs.com/RicCC)
// March 7, 2008
//===============================================================================

using Antlr.Runtime;

namespace SQLAnalyticLibrary.Expressions
{
    /// <summary>
    /// Table, column, and function name
    /// <remarks>
    /// </remarks>
    /// </summary>
    public class Table : Expression
    {
        private string _tableName = null;
        private Alias _alias = null;

        /// <summary>
        /// four types of subtree tokens: Identifier(table name), SelectStatement & UnionStatement(sub queries), Alias
        /// </summary>
        /// -> ^(Table subQuery alias?) or ^(Table identifier alias?)
        /// <param name="t"></param>
        public Table(IToken t)
            : base(t)
        {
            this.Token.Text = "";
        }
        public Table(Expression t)
            : base(t.Token)
        {
            Table tab = t as Table;
            if (tab != null)
            {
                this._alias = tab._alias;
                this._tableName = tab._tableName;
            }
        }
        public override Expression DupNode()
        {
            return new Table(this);
        }
        private void SetValue(Expression exp)
        {
            if (Identifier.IsIdentifier(exp))
            {
                Identifier identif = (exp as Identifier);
                if (identif != null)
                {
                    this._tableName = identif.Name;
                }
                Alias alias = exp as Alias;
                if (alias != null)
                {
                    this._alias = alias;
                }
                if (this.TokenStartIndex > 0 && this.TokenStartIndex > exp.TokenStartIndex)
                {
                    this.TokenStartIndex = exp.TokenStartIndex;
                }
                int end = GetMaxStopIndex(exp);
                this.TokenStopIndex = end;
            }
            else if (SQLAnalyticLibrary.Expressions.Alias.IsAlias(exp))
            {
                this._alias = exp as SQLAnalyticLibrary.Expressions.Alias;
            }
            if (this.token == null || this.token.StopIndex == 0)
            {
                this.token = exp.Token;
            }
        }
        public override void AddChild(Expression t)
        {
            //possible type of t: null, Identifier, Alias, SelectStatement
            if (t == null ) return;
            bool isSelect = SelectStatement.IsSelectStatement(t);
            if (!isSelect)
            {
                if (t._children != null)
                    foreach (Expression exp in t._children)
                        if (SelectStatement.IsSelectStatement(exp))
                        {
                            isSelect = true;
                            break;
                        }
            }
            if (isSelect)
            {
                //only SelectStatement is added to children.
                this.InternalAddChild(t);
                return;
            }
            this.SetValue(t);
            if (t._children != null && t._children.Count > 0)
                for (int i = 0; i < t._children.Count; i++)
                    this.SetValue(t._children[i]);
        }
        public bool IsSubQuery
        {
            get
            {  //TODO: if sub query is a union statement.
                return this._children != null && this._children.Count > 0 &&
                    (SelectStatement.IsSelectStatement(this._children[0]) || UnionStatement.IsUnionStatement(this._children[0]));
            }
        }
        public static bool IsTable(Expression exp)
        {
            if (exp == null || exp.IsNil) return false;
            return exp.Token.Type == OQLParser.Table;
        }
        public bool HasTableName
        {
            get
            {
                return !string.IsNullOrEmpty(this._tableName);
            }
        }
        public string TableName
        {
            get
            {
                return this._tableName;
            }
        }
        public bool HasAlias
        {
            get
            {
                return this._alias != null;
            }
        }
        public string AliasName
        {
            get
            {
                return HasAlias ? this._alias.Name : string.Empty;
            }
        }
        public override string ToString()
        {
            System.Text.StringBuilder builder = new System.Text.StringBuilder();
            if (!string.IsNullOrEmpty(this._tableName)) builder.Append(this._tableName);
            if (this._alias != null)
            {
                if (!string.IsNullOrEmpty(this._alias.ToString())) builder.Append(" ");
                builder.Append(this._alias.ToString());
            }
            return builder.ToString();
        }

        public override void VisitSql(ISqlVisitor visitor)
        {
            if (this.HasTableName) //try to identify table name.
                visitor.Table(this.TableName);
            if (this.IsSubQuery) //sub query
                this._children[0].VisitSql(visitor);
            if (this.HasAlias)
            {
                visitor.Space();
                this._alias.VisitSql(visitor);
            }
        }
    }
}